/*******************************************************************

  LaunchIPC.c
  
  Makes launching your own IPC_process so easy like possible
  (are we not all lazy ... ? ;) ). You does not need to declare
  any functions "__saveds" and/or "__asm" to launch a new process,
  this is all here done.
  
  You must have a global memorypool called "mempool" to use this
  like it is (, else you must change it a little bit...).
  
  The only thing you have to do, is to copy the prototype of
  LaunchIPC() ...
    
*********************************************************************/  
  
#include "includes/LaunchIPC.h" 

/********************************************************************/
// this you should declare in your other files

extern BOOL __saveds LaunchIPC( void (*func_entry)(), APTR data, IPCData **saveto, STRPTR proc_name, ULONG stack );

// arguments: 
// func_entry - your new process entry point...
//              your function must be the type "void name( IPCData *ipc, APTR data )"
//              and does reveive also its own IPC pointer as argument
// data       - any data you want to have as argument for your new process
//              but keep in mind that this data remains valid long enough...
// saveto     - a pointer to save the IPCData of the new process (must be supplied !) 
// proc_name  - name of the process name to create
// stack      - stack size to use for the new process (if NULL -> default 4096)

// the function does return TRUE on success

/********************************************************************/
// local prototypes

void __saveds Func_Startup( void );

ULONG __asm __saveds startup_startup( register __a0 IPCData   *ipc,
                                      register __a1 StartupData *cd );
                                                                                                 
/********************************************************************/
// all stuff is really simple, but it may save a lot of work,
// especially if you need more than one process.  

// this function does allocate some memory and launches the new process

BOOL __saveds LaunchIPC( void (*func_entry)(), APTR data, IPCData **saveto, STRPTR proc_name, ULONG stack )
{
     StartupData *sd;
          
     if( (sd = AllocMemH( mempool, sizeof(StartupData))) )
       {                   
          sd->a4      =                    getreg( REG_A4 );
          sd->module  = (struct Library *) getreg( REG_A6 );
          sd->library = DOpusBase;
          sd->entry   = func_entry;
          sd->data    = data;
                         
          if( !stack )
               stack = 4096;
                                                                     
          IPC_Launch( 0, saveto, proc_name,
                      (ULONG) Func_Startup, stack,
                      (ULONG) sd, DOSBase );
                                                         
          if( saveto )
               return TRUE;
                                
          FreeMemH( sd );                                                      
       }
                 
     return FALSE;
}

void __saveds Func_Startup( void )
{
     struct Library *DOpusBase;
     IPCData        *ipc;
     StartupData    *sd;
     
     if (!(DOpusBase=(struct Library *)FindName(&((struct ExecBase *)*((ULONG *)4))->LibList,"dopus5.library")))
         return;

     ipc = IPC_ProcStartup( (ULONG *) &sd, startup_startup);

     putreg( REG_A4, sd->a4 );

     if( ipc )
       {
          sd->module->lib_OpenCnt++;
                         
          sd->entry( ipc, sd->data );  // starting your function
                         
          sd->module->lib_OpenCnt--;
       }
                 
     IPC_Free( sd->ipc );
     FreeMemH( sd ); 
     return;
}

ULONG __asm __saveds startup_startup( register __a0 IPCData   *ipc,
                                      register __a1 StartupData *sd )
{
     struct Library *DOpusBase;
        
     putreg( REG_A4, sd->a4 );
     sd->ipc = ipc;
     DOpusBase = sd->library;  // does produce a warning here...
                  
     return TRUE;
}